/* Copyright (C) 2021 Rain */

/* This file is part of XNIX. */

/* 
  XNIX is free software: you can redistribute it and/or modify 
  it under the terms of the GNU General Public License as published by 
  the Free Software Foundation, either version 3 of the License, or 
  (at your option) and later version. 
*/

/*
  XNIX is distributed in the hope that it will be useful, 
  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  GNU General Public License for more details. 
*/

/*
  You should have received a copy of the GNU General Public License 
   along with XNIX. If not, see <https://www.gnu.org/licenses/>.  
*/




#ifndef _MM_H
#define _MM_H

#include <kernel/types.h>
#include <kernel/errno.h>

#include <lib/bitman.h>


extern void *_text, *_etext;
extern void *_data, *_edata;
extern void *_rodata, *_erodata;
extern void *_bss, *_ebss;
extern void *_end;

void mm_init(void);
void *alloc_page(void);
void *alloc_page_att(__uint64_t);
void free_page(void *);


#define E820_RAM 1
#define E820_ROM 2

/* we doesn't need other types, even they are present */

/* if >= E820_INV, break */
#define E820_INV 5


#define E820_ADDR ((struct e820_entry *) 0x7000)

struct e820_entry {
	__uint64_t addr;
	__uint64_t len;
	__uint32_t type;
} __attribute__ ((packed));


/* a memory zone that describes some pages */

struct zone {
	/* in e820 */
	__uint32_t type;
	__uint32_t total_pages;

	__uint32_t start_addr;
	__uint32_t end_addr;

	__uint32_t size;

	__uint32_t using;
};


struct sysmm {
	__uint64_t total_ram;
	__uint64_t total_pages;

	__uint32_t e820_count;
	struct e820_entry *e820;

	__uint32_t total_zones;
	struct zone *zones;

	__uint8_t *bitmap;
};

extern struct sysmm *mm;

#define PAGE_4K_SHIFT 12
#define PAGE_2M_SHIFT 21

#define PAGE_SHIFT PAGE_2M_SHIFT

#define PAGE_4K_SIZE (1ul << 12)
#define PAGE_2M_SIZE (1ul << 21)

#define PAGE_SIZE PAGE_2M_SIZE

#define PAGE_4K_MASK (~(PAGE_4K_SIZE - 1))
#define PAGE_2M_MASK (~(PAGE_2M_SIZE - 1))

#define PAGE_MASK PAGE_2M_MASK

#define PAGE_4K_ALIGN(a) ((a + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
#define PAGE_2M_ALIGN(a) ((a + PAGE_2M_SIZE - 1) & PAGE_2M_MASK)

#define PAGE_ALIGN(a) PAGE_2M_ALIGN(a)


/* slab-like memory management */

struct mempool {
	__uint64_t size;
	__uint64_t used;

	__uint64_t entries;

	__uint8_t *bitmap;

	void *page;

	struct mempool *next;
};

#define DEVPOOL_ENTRY_SIZE 	1024
#define DEVPOOL_ENTRY_SHIFT 	10ul

#define POOL_ENTRY_SIZE  	64
#define POOL_ENTRY_SHIFT	6ul

extern struct mempool pool;
extern struct mempool upool;
extern struct mempool devpool;


void *kmalloc(struct mempool *, __uint64_t);
void kfree(struct mempool *, void *, __uint64_t);
void *mapping(void *, __uint64_t);
void *mm_vphy(void *);


/* put memory info */

void trace_mm(void);

#define invalidate() __asm__ __volatile__ ("movq %%cr3, %%rax\n\tmovq %%rax, %%cr3\n\t" ::: "ax")
#define mfence() __asm__ __volatile__ ("mfence" ::: "memory")


#endif

